package xijia.plus.docs.thymeleafuser.util;


import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

/**
 * 导入导出 文件工具
 *
 * @author wangsong
 * @version 1.0.0
 * @email 1720696548@qq.com
 * @date 2022/12/22 0022 21:16
 */
@Slf4j
public class XjFileUtil {


    /**
     * 判断文件路径是否存在，不存在创建
     *
     * @param path
     * @return void
     * @date 2019/11/22 15:18
     */
    public static void mkdirFile(String path) {
        // 不存在创建文件夹
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 创建文件
     *
     * @param path 全路径 指向文件
     * @return
     */
    public static boolean makeFile(String path) {
        File file = new File(path);
        if (file.exists()) {
            log.info("文件已存在！");
            return false;
        }
        if (path.endsWith(File.separator)) {
            log.info("不能为目录！");
            return false;
        }
        if (!file.getParentFile().exists()) {
            if (!file.getParentFile().mkdirs()) {
                log.info("创建目标文件所在目录失败！");
                return false;
            }
        }
        try {
            if (file.createNewFile()) {
                log.info("创建文件" + path + "成功！");
                return true;
            } else {
                log.info("创建文件" + path + "失败！");
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.info("创建文件" + path + "失败！" + e.getMessage());
            return false;
        }
    }


    /**
     * MultipartFile 保存到本地
     *
     * @param multipartFile 上传文件
     * @param path          保存地址
     * @return 本地文件
     */
    public static void uploadFile(MultipartFile multipartFile, String path) {
        // 创建放文件的目录
        try {
            uploadFile(multipartFile.getInputStream(), path, multipartFile.getOriginalFilename());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * MultipartFile 保存到本地
     *
     * @param inputStream 上传文件
     * @param path        保存地址
     * @param filename    保存后的文件名
     * @return 本地文件
     */
    public static void uploadFile(InputStream inputStream, String path, String filename) {
        // 创建放文件的目录
        Path directory = Paths.get(path);
        try {
            // 判断目录是否存在，不存在创建
            if (!Files.exists(directory)) {
                Files.createDirectories(directory);
            }
            // 拷贝文件
            Files.copy(inputStream, directory.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 获取可访问的 url 的文件流
     * <p>
     * 通常作用于文件读取,如 图片/pdf/word等
     * 注意：该方法未关闭流
     * </P>
     *
     * @param filePath 可访问的url
     * @param fileName 获取后的文件名
     * @return void
     * @author wangsong
     * @date 2020/8/26 0026 17:00
     * @version 1.0.1
     */
    public static InputStream getInputStreamByUrl(String filePath, String fileName) {
        int index = filePath.lastIndexOf("/");
        String newFilePath = filePath.substring(0, index + 1);
        InputStream in = null;
        try {
            // 编码
            fileName = URLEncoder.encode(fileName.trim(), "utf-8");
            // 处理空格
            fileName = fileName.replaceAll("\\+", "%20");
            URL url = new URL(newFilePath + fileName);
            URLConnection conn = url.openConnection();
            in = conn.getInputStream();
            // in.close();
        } catch (IOException e) {
            log.error("错误： 尝试使用原连接获取");
            try {
                // 编码
                URL url = new URL(filePath);
                URLConnection conn = url.openConnection();
                in = conn.getInputStream();
                log.error("使用原连接获取成功");
            } catch (IOException e1) {
                log.error(e1.toString());
                log.error("使用原连接获取失败");
            }
        }
        return in;
    }

    /**
     * 通过 url 获取文件流
     *
     * <p>
     * 通常作用于静态文件模板内容读取，如 .tp .txt 等
     * 注意：该方法未关闭流
     * </P>
     *
     * @param urlStr
     * @return java.lang.String
     * @author ws
     * @mail 1720696548@qq.com
     * @date 2020/2/9 0009 21:01
     */
    public static BufferedReader getBufferedReaderByUrl(String urlStr) throws Exception {
        URL url = new URL(urlStr);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        httpConn.connect();
        InputStream cin = httpConn.getInputStream();
        return new BufferedReader(new InputStreamReader(cin, StandardCharsets.UTF_8));
    }

    /**
     * 关闭流
     *
     * @author wangsong
     * @email 1720696548@qq.com
     * @date 2023/1/18 0018 11:47
     * @version 1.0.0
     */
    public static void close(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }


    /**
     * 获取 resources | classpath 下指定的文件 (不能获取文件夹)
     *
     * @author wangsong
     * @email 1720696548@qq.com
     * @date 2022/12/22 0022 21:06
     * @version 1.0.0
     */
    public static InputStream getInputStreamByClasspath(String path) {
        // InputStream in = String.class.getClassLoader().getResourceAsStream(path);
        Resource resource = new ClassPathResource(path);
        try {
            return resource.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 复制单个文件 从classpath中读取文件复制
     *
     * @param path    不能以/开头   指向文件不能是目录
     * @param newPath 指向文件不能是目录
     */
    public static void copyFileByClasspath(String path, String newPath) {
        InputStream in = getInputStreamByClasspath(path);
        try {
            //创建新文件
            makeFile(newPath);
            //将流写入新文件
            write(in, newPath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取 classpath 下指定的文件 (不能获取文件夹)
     *
     * @author wangsong
     * @email 1720696548@qq.com
     * @date 2022/12/22 0022 21:06
     * @version 1.0.0
     */
    public static FileInputStream getFileInputStreamByClasspath(String path) {
        // 读取目录文件打压缩包
        try {
            return new FileInputStream(ResourceUtils.getURL("classpath:").getPath() + "/" + path);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 输入流写入文件
     *
     * @param in       输入流
     * @param filePath 文件保存目录路径
     * @throws IOException
     */
    public static void write(InputStream in, String filePath) throws IOException {
        OutputStream os = Files.newOutputStream(Paths.get(filePath));
        int len = 8192;
        byte[] buffer = new byte[len];
        while ((len = in.read(buffer, 0, len)) != -1) {
            os.write(buffer, 0, len);
        }
        os.close();
        in.close();
    }


    /**
     * InputStream 转  file (getClasspathFile 获取的文件流可以通过这个方法保存到指定位置中)
     * 只支持单个文件
     *
     * @param ins 文件流
     * @param mkdir 文件路径
     * @param fileName 文件名称
     */
    public static File inputStreamToFile(InputStream ins, String mkdir, String fileName) {
        File file = new File(mkdir);
        // 创建放文件的目录
        if (!file.exists()) {
            file.mkdirs();
        }
        OutputStream os = null;
        try {
            file = new File(mkdir + "/" + fileName);
            // 创建放文件的目录
            if (!file.exists()) {
                file.createNewFile();
            }
            os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                os.close();
                ins.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return file;
    }

}
